
#ifndef _POINT_
#define _POINT_

#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>

using namespace std;

void abort(int error_code)
{
    switch (error_code)
    {
    case 1:
	cout << "Dimension is not matched!" << endl;break;
    case 2:
	cout << "Out of index!" << endl;break;
    case 3:
        cout << "to be continued!" << endl;break;
    default:
	break;
    }
    exit(-1);
};
/**
 *@brief Point<DIM>点类
 *
 */
template<unsigned int DIM>
class Point
{
private:
    double value[DIM];/*<存储各个维度的坐标 */
public:
   /**
    *@brief 无参构造函数
    *
    */
    Point();
    /**
     * @brief 左值引用含参构造函数。
     *
     * @param Point_vector:左值引用，包含下标。
     */
    Point(const vector<double>& Point_vector);
    /**
     * @brief 右值引用含参构造函数。
     *
     * @param Point_vector:右值引用，包含下标。
     */
    Point(vector<double>&& Point_vector);
    /**
     * @brief 初始化列表含参构造函数。
     *
     * @param Point_list:初始化列表。
     */
    Point(const std::initializer_list<double>& Point_list);
    /**
     * @brief 默认析构函数
     *
     */
    ~Point() = default;
    /**
     * @brief: 重载[]操作符
     *
     * @param d 第d个维度
     *
     * @return 第d个维度的坐标
     */
    double& operator[](const unsigned int d);
    const double& operator[](const unsigned int d) const;
    /**
     * @brief 友元函数，输出Point
     *
     * @param os:ostream
     * @param p:Point<DIM>
     *
     * @return
     */
    template<unsigned int D>
    friend ostream& operator<<(ostream& os, const Point<D> & p);
    /**
     * @brief 友元函数，计算两点间距离。
     *
     * @param p1:Point<DIM>
     * @param p2:Point<DIM>
     *
     * @return
     */
    template<unsigned int D>
    friend double getDistance(const Point<D> p1, const Point<D> p2);
};

template<unsigned int DIM>
Point<DIM>::Point()  
{  
    fill(value, value + DIM, static_cast<double>(0));
};

template<unsigned int DIM>
Point<DIM>::Point(const vector<double>& p_vector)
{
    if(p_vector.size() != DIM)
    {
       abort(1);
    }
    vector<double>::const_iterator i_begin = p_vector.begin();
    vector<double>::const_iterator i_end = p_vector.end();
    copy(i_begin, i_end, value);
};

template<unsigned int DIM>
Point<DIM>::Point(vector<double>&& p_vector)
{
    if(p_vector.size() != DIM)
    {
       abort(1);
    }
    vector<double>::const_iterator i_begin = p_vector.begin();
    vector<double>::const_iterator i_end = p_vector.end();
    copy(i_begin, i_end, value);//还是复制了，考虑把数组改成vector
	p_vector.clear();
};

template<unsigned int DIM>
Point<DIM>::Point(const initializer_list<double>& Point_list)
{
    if(Point_list.size() != DIM)
    {
        abort(1);
    }
    initializer_list<double>::const_iterator i_begin = Point_list.begin();
    initializer_list<double>::const_iterator i_end = Point_list.end();
    copy(i_begin, i_end,value);
};
//@}
template<unsigned int DIM>
double& Point<DIM>::operator[](const unsigned int d)
{
    return value[d];
}
template<unsigned int DIM>
const double& Point<DIM>::operator[](const unsigned int d) const
{
    return value[d];
}

template<unsigned int D>
ostream& operator<<(ostream& os, const Point<D> & p)
{
    os << "(";
    for(unsigned int d = 0; d < D - 1; d++)
    {
        os << p.value[d] << ", ";
    }
    os << p.value[D - 1] << ")";
    return os;
}

template<unsigned int D>
double getDistance(const Point<D> p1, const Point<D> p2)
{
    double temp;
    for(unsigned int d = 0; d < D; d++)
        temp += (p1[d] - p2[d]) * (p1[d] - p2[d]);
    return sqrt(temp);
}

#else 
// DO NOTHING.
#endif
